# -*- coding:utf-8 -*-
import json
from obs import ObsClient
import traceback
from obs import AppendObjectContent


def handler(event, context):
    log = context.getLogger()
    emq_data_handler = EMQDataHandler(context)
    try:
        result = emq_data_handler.run(event['records'][0])
        return result
    except Exception as e:
        exec_info = traceback.format_exc()
        log.error(f"failed to run emq data handler: {exec_info}")
        raise e
    finally:
        emq_data_handler.obs_client.close()


def get_data_time(vin_data):
    year_month_day = vin_data['时间'].split(' ')[0]
    hour = vin_data['时间'].split(' ')[1].split(':')[0]
    return year_month_day + "|" + hour


def get_vin_data_dict(record):
    messages = record['messages']
    vin_data_dict = {}
    for message in messages:
        m = json.loads(message)
        vin_data = json.loads(m['payload'])
        vin = vin_data['vin']
        data_time = get_data_time(vin_data)
        key = vin + "_" + data_time
        if key in vin_data_dict:
            v_list = vin_data_dict[key]
            v_list.append(m['payload'])
        else:
            v_list = [m['payload']]
            vin_data_dict[key] = v_list
    return vin_data_dict


class EMQDataHandler:

    def __init__(self, context):
        self.logger = context.getLogger()
        obs_endpoint = context.getUserData("obs_endpoint")
        self.obs_client = new_obs_client(context, obs_endpoint)
        self.target_bucket = context.getUserData("target_bucket")
        self.target_prefix = context.getUserData("target_prefix", "")

    def run(self, record):
        vin_data_dict = get_vin_data_dict(record)
        for key in vin_data_dict:
            object_key = self.get_object_key(key)
            retry = 0
            while True:
                try:
                    self.put_vin_data(object_key, vin_data_dict[key])
                    break
                except Exception:
                    if retry >= 3:
                        break
                    retry = retry +1

        return 'SUCCESS'

    def get_object_key(self, key):
        splits = key.split("_")
        vin = splits[0]
        time = splits[1]
        return self.target_prefix + "/" + vin + "/" + time + ".txt"

    def put_vin_data(self, object_key, data):
        resp = self.obs_client.getObjectMetadata(self.target_bucket,
                                                 object_key)
        if resp.status < 300:
            next_position = resp.body.nextPosition
        elif resp.status == 404:
            next_position = 0
        else:
            error_info = f'failed to appendObject {object_key} metadata, ' \
                         f'requestId: {resp.requestId}, ' \
                         f'errorCode: {resp.errorCode}'
            raise Exception(error_info)

        content = AppendObjectContent()
        content.position = next_position
        content.content = "\n".join(data) + "\n"
        resp = self.obs_client.appendObject(self.target_bucket,
                                            object_key, content)
        if resp.status > 300:
            error_info = f'failed to appendObject {object_key}, ' \
                         f'requestId: {resp.requestId}, ' \
                         f'errorCode: {resp.errorCode}'
            raise Exception(error_info)


def new_obs_client(context, obs_server):
    ak = context.getAccessKey()
    sk = context.getSecretKey()
    return ObsClient(access_key_id=ak, secret_access_key=sk, server=obs_server)